﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Neuron.Cell;
using System.Windows.Forms;
using System.IO;

namespace Neuron.Cell.Control
{

    public delegate void delegateUpdateFilename(string filename);

    public partial class ctrlTeachingConsole : UserControl
    {

        int _learningCounter = 0;
        int _learningSteps = 0;
        bool _actionAllowed = true;
        int _resultColumn = 1;

        Panel _drawingBoard = null;

        public delegate void delegateStepPerformed();
        public event delegateStepPerformed StepDone;

        private string _filename = "none";

        public event delegateUpdateFilename FilenameUpdated;

        private PerceptronBackbone _backbone = null;

        public ctrlTeachingConsole()
        {
            InitializeComponent();

            listViewTeaching.Columns.Add("Step");
            listViewTeaching.Columns.Add("Status");

            toolTipTrainingConsole.SetToolTip(btnInsertLine, "Adds a line of training data entered in the left textbox to the grid above.");
            toolTipTrainingConsole.SetToolTip(btnDelete, "Select a line in the trining grid above and press this button to remove the selected line.");
            toolTipTrainingConsole.SetToolTip(btnClearGrid, "Clears the complete grid above.");

            toolTipTrainingConsole.SetToolTip(btnLoad, "Loads traing values previously saved into the training grid");
            toolTipTrainingConsole.SetToolTip(btnSave, "Saves the complete training data from the training grid.");
            toolTipTrainingConsole.SetToolTip(btnStartTeaching, "Starts processing the training steps defined in the grid.");
            toolTipTrainingConsole.SetToolTip(btnStopTeaching, "Stopps the training process.");

            toolTipTrainingConsole.SetToolTip(textBoxInput, "Enter the training data here and press. 'Insert Line' to move the data from here to the grid.");
            toolTipTrainingConsole.SetToolTip(listViewTeaching, "This grid contains the training data for the perceptron network.");

        }

        public void setBackbone(PerceptronBackbone backbone)
        {
            this._backbone = backbone;
        }

        private bool isAlreadyGridColumn(string text)
        {
            for (int index = 0; index < listViewTeaching.Columns.Count; index++)
            {
                string header = listViewTeaching.Columns[index].Text;
                if (header == text)
                {
                    return true;
                }
            }
            return false;
        }

        private bool learningSucceeded()
        {
            bool result = true;

            for (int index = 0; index < listViewTeaching.Items.Count; index++)
            {
                if (listViewTeaching.Items[index].SubItems[this._resultColumn].Text == "NOK")
                {
                    return false;
                }
            }

            return result;
        }

        private void fillComboBox()
        {
            comboBoxPerceptrons.Items.Clear();
            comboBoxPerceptrons.Text = "";

            foreach (System.Windows.Forms.Control ctrlChild in this._drawingBoard.Controls)
            {
                if (ctrlChild is ctrlPerceptron)
                {
                    ctrlPerceptron tmpCtrlPerceptron = (ctrlPerceptron)ctrlChild;
                    Perceptron tmpPerceptron = tmpCtrlPerceptron.Perceptron;
                    if ((tmpPerceptron.ActivationFunction == ActivationFunctionEnum.actor) || (tmpPerceptron.ActivationFunction == ActivationFunctionEnum.receptor))
                    {
                        if (!this.isAlreadyGridColumn(tmpPerceptron.Name))
                        {
                            comboBoxPerceptrons.Items.Add(tmpPerceptron.Name);
                        }
                    }
                }
            }
        }

        private void comboBoxPerceptrons_MouseClick(object sender, MouseEventArgs e)
        {
            this.fillComboBox();
        }

        private void btnAddColumn_Click(object sender, EventArgs e)
        {
            if (comboBoxPerceptrons.Text.Trim() != "")
            {
                string newColumnHeader = comboBoxPerceptrons.Text;
                listViewTeaching.Columns.Insert(1, newColumnHeader);
                this._resultColumn += 1;
            }
        }

        private void buttonInsertLine_Click(object sender, EventArgs e)
        {
            this.InsertLine();
        }

        private void btnDelete_Click(object sender, EventArgs e)
        {
            this.DeleteLine();
        }

        private void btnStartTeaching_Click(object sender, EventArgs e)
        {
            this.StartTraining();
        }

        private void performCalculation()
        {
            if (this._actionAllowed == false) return;

            this._actionAllowed = false;

            if (this.learningSucceeded() == true)
            {
                btnStartTeaching.Enabled = true;
                timerPerformTeaching.Enabled = false;
                btnDelete.Enabled = true;
                btnInsertLine.Enabled = true;
                this._learningCounter = 0;
                textBoxMsg.Text = "Learning completed (Step: " + this._learningSteps.ToString() + ")";
                return;
            }
            textBoxMsg.Text = "Learning ongoing (Counter: " + this._learningCounter.ToString() + "/ Step: " + this._learningSteps.ToString() +  ")";

            if (this._learningCounter >= listViewTeaching.Items.Count)
            {
                this._learningCounter = 0;
            }

            ListViewItem lvi = listViewTeaching.Items[this._learningCounter];

            string strResult = "";
            double dblResult = 0.0;

            // Setze receptoren
            for (int index=0; index < lvi.SubItems.Count - 1; index++)
            {
                string strValue = lvi.SubItems[index].Text.ToString();
                double dblValue = Double.Parse(strValue.Replace('.', ','), System.Globalization.CultureInfo.InvariantCulture);
                //Convert.ToDouble(strValue);

                string strName = listViewTeaching.Columns[index].Text;
                foreach (System.Windows.Forms.Control ctrl in this._drawingBoard.Controls)
                {
                    if (ctrl is ctrlPerceptron)
                    {
                        ctrlPerceptron tmpCtrlP = (ctrlPerceptron)ctrl;
                        Perceptron tmpP = tmpCtrlP.Perceptron;
                        
                        if ((tmpP.Name.ToUpper() == strName.ToUpper())&&(tmpP.ActivationFunction == ActivationFunctionEnum.receptor))
                        {
                            tmpP.stimulate(dblValue);
                        }
                    }

                }
            }

            // Vergleiche actoren
            bool resultOK = true;

            for (int index = 0; index < lvi.SubItems.Count - 1; index++)
            {
                string strValue = lvi.SubItems[index].Text.ToString();
                double dblValue = Double.Parse(strValue.Replace('.', ','), System.Globalization.CultureInfo.InvariantCulture);
                //Convert.ToDouble(strValue);

                string strName = listViewTeaching.Columns[index].Text;
                foreach (System.Windows.Forms.Control ctrl in this._drawingBoard.Controls)
                {
                    if (ctrl is ctrlPerceptron)
                    {
                        ctrlPerceptron tmpCtrlP = (ctrlPerceptron)ctrl;
                        Perceptron tmpP = tmpCtrlP.Perceptron;

                        if ((tmpP.Name.ToUpper() == strName.ToUpper()) && (tmpP.ActivationFunction == ActivationFunctionEnum.actor))
                        {
                            if ((tmpP.VectorOUT == dblValue)&&(resultOK == true))
                            {
                                // Do nothing, keep result equal true                                
                            } else
                            {
                                // Provide feedback to final actor
                                tmpP.GiveFeedback(dblValue);
                                resultOK = false;
                            }
                        }
                    }
                }

            }

            for (int index = 0; index < lvi.SubItems.Count; index++)
            {
                if (listViewTeaching.Columns[index].Text.ToUpper() == "STATUS")
                {
                    if (resultOK == true)
                    {
                        lvi.SubItems[index].Text = "OK";
                    } else
                    {
                        lvi.SubItems[index].Text = "NOK";
                    }
                }
            }



            this._learningCounter += 1;
            this._learningSteps += 1;

            this._actionAllowed = true;

            if (this.StepDone != null)
            {
                this.StepDone();
            }
        }

        private void timerPerformTeaching_Tick(object sender, EventArgs e)
        {
            this.performCalculation();

        }

        public void LoadScript(object sender, EventArgs e)
        {
            this.btnLoad_Click(sender, e);
        }

        public void SaveScript(object sender, EventArgs e)
        {
            this.btnSave_Click(sender, e);
        }

        public void ClearGrid(object sender, EventArgs e)
        {
            this.btnClearGrid_Click(sender, e);
        }

        public void StartTraining()
        {
            this._learningCounter = 0;
            this._learningSteps = 0;
            this._actionAllowed = true;

            btnStartTeaching.Enabled = false;
            btnDelete.Enabled = false;
            btnInsertLine.Enabled = false;

            for (int i = 0; i < listViewTeaching.Columns.Count; i++)
            {
                string colName = listViewTeaching.Columns[i].Text.ToUpper();
                if (colName == "STATUS")
                {
                    this._resultColumn = i;

                    foreach (ListViewItem lvi in listViewTeaching.Items)
                    {
                        lvi.SubItems[this._resultColumn].Text = "NOK";
                    }
                }
            }

            /*
            if (timerPerformTeaching.Enabled)
            {
                timerPerformTeaching.Enabled = false;
                return;
            }
            */

            if (listViewTeaching.Items.Count > 0)
            {
                timerPerformTeaching.Enabled = true;
            }
            else
            {
                timerPerformTeaching.Enabled = false;
            }
        }

        public void StopTraining()
        {
            timerPerformTeaching.Enabled = false;

            btnStartTeaching.Enabled = true;
            btnDelete.Enabled = true;
            btnInsertLine.Enabled = true;

            this._actionAllowed = true;
        }

        public void InsertLine()
        {
            string newLine = textBoxInput.Text;
            string[] arrParts = newLine.Split(',');
            for (int i = 0; i < arrParts.Count(); i++)
            {
                arrParts[i] = arrParts[i].Trim(',').Trim(' ');
            }

            int countItems = listViewTeaching.Items.Count + 1;
            ListViewItem itemNew = new ListViewItem(countItems.ToString());
            foreach (string strPart in arrParts)
            {
                itemNew.SubItems.Add(strPart);
            }
            itemNew.SubItems.Add("NOK");
            listViewTeaching.Items.Add(itemNew);

            textBoxInput.Text = "";
            textBoxInput.Focus();
        }

        public void DeleteLine()
        {
            if (listViewTeaching.SelectedIndices.Count == 0) return;

            int selIndex = listViewTeaching.SelectedIndices[0];
            listViewTeaching.Items.RemoveAt(selIndex);
        }

        public void UpdateGrid(object sender, EventArgs e)
        {
            this.buttonUpdate_Click(sender, e);
        }

        public void UpdateGrid()
        {
            listViewTeaching.Columns.Clear();
            listViewTeaching.Columns.Add("Step");

            foreach (System.Windows.Forms.Control ctrlChild in this._drawingBoard.Controls)
            {
                if (ctrlChild is ctrlPerceptron)
                {
                    ctrlPerceptron tmpCtrlPerceptron = (ctrlPerceptron)ctrlChild;
                    Perceptron tmpPerceptron = tmpCtrlPerceptron.Perceptron;
                    if (tmpPerceptron.ActivationFunction == ActivationFunctionEnum.receptor)
                    {
                        listViewTeaching.Columns.Add(tmpPerceptron.Name);
                    }
                }
            }

            foreach (System.Windows.Forms.Control ctrlChild in this._drawingBoard.Controls)
            {
                if (ctrlChild is ctrlPerceptron)
                {
                    ctrlPerceptron tmpCtrlPerceptron = (ctrlPerceptron)ctrlChild;
                    Perceptron tmpPerceptron = tmpCtrlPerceptron.Perceptron;
                    if (tmpPerceptron.ActivationFunction == ActivationFunctionEnum.actor)
                    {
                        listViewTeaching.Columns.Add(tmpPerceptron.Name);
                    }
                }
            }

            //this.SearchRecursive(this._drawingBoard);

            listViewTeaching.Columns.Add("Status");
        }


        private void btnStopTeaching_Click(object sender, EventArgs e)
        {
            this.StopTraining();
        }

        private void btnLoad_Click(object sender, EventArgs e)
        {
            this._filename = "none";
            openFileDialog.Filter = "Neural Network Designer Script|*.nnd";
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                listViewTeaching.Clear();

                StreamReader file = new StreamReader(openFileDialog.FileName);
                if (!file.EndOfStream)
                {
                    string line = file.ReadLine();
                    string[] arrLine = line.Split(',');
                    for (int i = 0; i < arrLine.Count(); i++)
                    {
                        arrLine[i] = arrLine[i].Trim(';').Trim(' ');
                        listViewTeaching.Columns.Add(arrLine[i]);

                        // Beim Aufbau des Headers die Resultspalte "wegschreiben"
                        if (arrLine[i].ToUpper() == "STATUS")
                        {
                            this._resultColumn = i;
                        }
                    }
                    while (!file.EndOfStream)
                    {
                        line = file.ReadLine();
                        arrLine = line.Split(',');
                        ListViewItem lvi = null;
                        for (int i = 0; i < arrLine.Count(); i++)
                        {
                            arrLine[i] = arrLine[i].Trim(';').Trim(' ');
                            if (i == 0)
                            {
                                lvi = new ListViewItem(arrLine[i]);
                            } else
                            {
                                lvi.SubItems.Add(arrLine[i]);
                            }
                        }
                        // Fuege Eintrag ins Grid ein
                        if (lvi != null)
                        {
                            listViewTeaching.Items.Add(lvi);
                        }
                    }

                    // Jetzt die evtl. geladene Resulatet auf NOK setzen, damit das neue Anlernen 
                    // gestartet werden kann
                    for (int i = 0; i < listViewTeaching.Items.Count; i++)
                    {
                        listViewTeaching.Items[i].SubItems[this._resultColumn].Text = "NOK";
                    }
                }
                this._filename = Path.GetFileName(openFileDialog.FileName);
                if (this.FilenameUpdated != null)
                {
                    this.FilenameUpdated(this._filename);
                }
            }

            // Adapt lisviewheader to match the loaded script
            //this.UpdateTableHeader();
            this.UpdateGrid();

            // Neues Skript: alles auf Anfang
            this._actionAllowed = true;
            this._learningCounter = 0;
            this._learningSteps = 0;

        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            saveFileDialog.Filter = "Neural Network Designer Script|*.nnd";
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                // Öffne Filestream, um die Savedatei anzulegen
                StreamWriter file = new StreamWriter(saveFileDialog.FileName);

                // Schreibe den Header in die Datei
                string strHeadline = "";
                int colCount = listViewTeaching.Columns.Count;
                for (int i=0; i < colCount; i++)
                {
                    strHeadline += listViewTeaching.Columns[i].Text;
                    if (i < colCount - 1)
                    {
                        strHeadline += ",";
                    }
                }
                strHeadline += ";";
                file.WriteLine(strHeadline);

                // Schreibe die Inhalte des Grids in die Datei
                foreach (ListViewItem lvi in listViewTeaching.Items)
                {
                    string lineOfText = "";
                    for (int j = 0; j < colCount; j++)
                    {
                        lineOfText += lvi.SubItems[j].Text;
                        if (j < colCount - 1)
                        {
                            lineOfText += ",";
                        }
                    }
                    lineOfText += ";";
                    file.WriteLine(lineOfText);
                }

                // Schliesse die Datei
                file.Flush();
                file.Close();
            }
        }

        private void btnClearGrid_Click(object sender, EventArgs e)
        {
            listViewTeaching.Items.Clear();
            this.buttonUpdate_Click(sender, e);

            this._filename = "none";
            if (this.FilenameUpdated != null)
            {
                this.FilenameUpdated(this._filename);
            }
        }

        private void SearchRecursive(System.Windows.Forms.Control parent)
        {
            foreach (System.Windows.Forms.Control ctrlChild in parent.Controls)
            {
                if (ctrlChild is ctrlPerceptron)
                {
                    ctrlPerceptron tmpCtrlPerceptron = (ctrlPerceptron)ctrlChild;
                    Perceptron tmpPerceptron = tmpCtrlPerceptron.Perceptron;
                    if (tmpPerceptron.ActivationFunction == ActivationFunctionEnum.actor)
                    {
                        listViewTeaching.Columns.Insert(1, tmpPerceptron.Name);
                    }
                }
            }

            if (parent.Parent != null)
            {
                this.SearchRecursive(parent.Parent);
            }
        }

        /*
        public void UpdateTableHeader()
        {
            listViewTeaching.Columns.Clear();
            listViewTeaching.Columns.Add("Step");

            foreach (System.Windows.Forms.Control ctrlChild in this._drawingBoard.Controls)
            {
                if (ctrlChild is ctrlPerceptron)
                {
                    ctrlPerceptron tmpCtrlPerceptron = (ctrlPerceptron)ctrlChild;
                    Perceptron tmpPerceptron = tmpCtrlPerceptron.Perceptron;
                    if (tmpPerceptron.ActivationFunction == ActivationFunctionEnum.receptor)
                    {
                        listViewTeaching.Columns.Add(tmpPerceptron.Name);
                    }
                }
            }

            foreach (System.Windows.Forms.Control ctrlChild in this._drawingBoard.Controls)
            {
                if (ctrlChild is ctrlPerceptron)
                {
                    ctrlPerceptron tmpCtrlPerceptron = (ctrlPerceptron)ctrlChild;
                    Perceptron tmpPerceptron = tmpCtrlPerceptron.Perceptron;
                    if (tmpPerceptron.ActivationFunction == ActivationFunctionEnum.actor)
                    {
                        listViewTeaching.Columns.Add(tmpPerceptron.Name);
                    }
                }
            }

            //this.SearchRecursive(this._drawingBoard);

            listViewTeaching.Columns.Add("Status");
        }
        */

        public Panel DrawingBoard
        {
            get { return this._drawingBoard;  }
            set { this._drawingBoard = value; }
        }

        private void buttonUpdate_Click(object sender, EventArgs e)
        {
            //this.UpdateTableHeader();
            this.UpdateGrid();
        }
    }
}
